package com.ynhenc.pta.routeRank.impl;

import com.ynhenc.pta.routeRank.*;

import java.io.*;

public class RouteRankImpl_Random extends RouteRankImpl {

	public RouteRankImpl_Random(RouteRequest routeRequest) {
		super(routeRequest);
	}

	public String getCode() {
		return "RND";
	}

	public RouteResultImpl getRouteResult_Shortest(RouteRequest routeRequest) throws Exception {
		RouteSearchType routeSearchType = RouteSearchType.SHORTEST;

		StartEndNodeList seNodeList = this.getScenario().getStartEndNodeList_01_Shortest(routeRequest);

		return this.getRouteResult(routeRequest, routeSearchType, seNodeList);
	}

	public RouteResultImpl getRouteResult_Green_01(RouteRequest routeRequest) throws Exception {
		// 지하철 경로 탐색

		RouteSearchType routeSearchType = RouteSearchType.GREEN_01;

		StartEndNodeList seNodeList = this.getScenario().getStartEndNodeList_02_Green_01(routeRequest);

		RouteResultImpl routeResult = this.getRouteResult(routeRequest, routeSearchType, seNodeList);

		Node oa = routeRequest.getNodeStart();
		Node ta = routeResult.getNodeStart();
		Node tb = routeResult.getNodeEnd();
		Node ob = routeRequest.getNodeEnd();

		if (ta == null || tb == null) {
			int pos = 0;
			double dist_Meter = ob.getDirectDistance_Meter( ob ); 
			TransitType transitType = TransitType.BUS; 
			if( dist_Meter > 2000 ) { 
				transitType = TransitType.AUTOMOBILE;
			} else if( dist_Meter > 500 ) {
				transitType = TransitType.BIKE;
			} else {
				transitType = TransitType.WALK;
			}
			SectionList sectionList_Walk = this.linkSection(transitType, ob, ob, routeRequest);
			if (sectionList_Walk != null) {
				routeResult.addSectionList(sectionList_Walk, pos);
			}
		} else {

			TransitType basicTransit = routeRequest.getBasicTransitType();

			if (basicTransit == TransitType.AUTOMOBILE) { // 기본 운송 수단이 차이면 보행으로
				// 설정한다.
				basicTransit = TransitType.WALK;
			}

			if (true) { // link section from OA -> TA
				int pos = 0;

				double distCurv = oa.getDirectDistance_Meter(ta);
				TransitType transitType = basicTransit;

				if (distCurv > 2000) { // 거리가 2KM 이상이면 .....
					transitType = TransitType.BUS;
					SectionList sectionList_Bus = this.linkSection(transitType, oa, ta, routeRequest);
					if (sectionList_Bus != null) { // 버스 노선이 있으면 버스로 간다.
						routeResult.addSectionList(sectionList_Bus, pos);
						Node busStopStart = sectionList_Bus.getNodeStart();
						double distToBusStop = oa.getDirectDistance_Meter(busStopStart);
						if (distToBusStop > 20) { // 시작점부터 버스 출발점 까지 연결.
							SectionList sectionList_Walk = this.linkSection(TransitType.WALK, oa, busStopStart, routeRequest);
							if (sectionList_Walk != null) {
								routeResult.addSectionList(sectionList_Walk, pos);
							}
						}
					} else { // 버스 노선이 없으면 차로 간다.
						SectionList sectionList_Auto = this.linkSection(TransitType.AUTOMOBILE, oa, ta, routeRequest);
						if (sectionList_Auto != null) {
							routeResult.addSectionList(sectionList_Auto, pos);
						}
					}
				} else if (distCurv > 500) { // && basicTransit ==
												// TransitType.BIKE
					// 자전거로 지하철 역까지 이동.
					transitType = TransitType.BIKE;
					SectionList sectionList = this.linkSection(transitType, oa, ta, routeRequest);
					if (sectionList != null) {
						routeResult.addSectionList(sectionList, pos);
					}
				} else { // 도보로 지하철역까지 이동.
					transitType = TransitType.WALK;
					SectionList sectionList = this.linkSection(transitType, oa, ta, routeRequest);
					if (sectionList != null) {
						routeResult.addSectionList(sectionList, pos);
					}
				}
			}
			if (true) { // linek section TB -> OB , 지하철 역 도착후....
				int pos = -1;
				double dist = ob.getDirectDistance_Meter(tb);
				if (dist > 700) { // 거리가 500 미터 이상이면 버스로 이동.
					TransitType transitType = TransitType.BUS;
					SectionList sectionList_Bus = this.linkSection(transitType, tb, ob, routeRequest);
					if (sectionList_Bus != null) {
						if (sectionList_Bus.getSize() > 2 || sectionList_Bus.getSize() < 1) {
							// 버스 노선이 없거나 두번 이상 갈아 타면 .....
							transitType = TransitType.WALK;
							SectionList sectionList_Walk = this.linkSection(transitType, tb, ob, routeRequest);
							if (sectionList_Walk != null) {
								routeResult.addSectionList(sectionList_Walk, pos);
							}
						} else {
							routeResult.addSectionList(sectionList_Bus, pos);
							Node busStopEnd = sectionList_Bus.getNodeEnd();
							double distToBusStop = busStopEnd.getDirectDistance_Meter(ob);
							if (distToBusStop > 20) {
								// 버스 하차후 도착지 까지 걸어서 감.
								SectionList sectionList_Walk = this.linkSection(TransitType.WALK, busStopEnd, ob, routeRequest);
								if (sectionList_Walk != null) {
									routeResult.addSectionList(sectionList_Walk, pos);
								}
							}
						}
					}
				} else {
					TransitType transitType = TransitType.WALK;
					SectionList sectionList_Walk = this.linkSection(transitType, tb, ob, routeRequest);
					if (sectionList_Walk != null) {
						routeResult.addSectionList(sectionList_Walk, pos);
					}
				}
			} 
		}

		return routeResult;
	}

	public RouteResultImpl getRouteResult_Green_02(RouteRequest routeRequest) throws Exception {
		// 버스 경로 탐색
		// 출발지 -> 환승점 까지 도보 연결 , 최단 거리가 직선거리 보다 일정 비율 이상이면 직선으로 연결.
		// 환승점 -> 목적리 까지 도보 연결 , 최단 거리가 직선거리 보다 일정 비율 이상이면 직선으로 연결.
		RouteSearchType routeSearchType = RouteSearchType.GREEN_02;

		StartEndNodeList seNodeList = this.getScenario().getStartEndNodeList_03_Green_02(routeRequest);

		RouteResultImpl routeResult = this.getRouteResult(routeRequest, routeSearchType, seNodeList);

		Node oa = routeRequest.getNodeStart();
		Node ta = routeResult.getNodeStart();
		Node tb = routeResult.getNodeEnd();
		Node ob = routeRequest.getNodeEnd();

		if (true) { // link section from OA -> TA
			TransitType transitType = TransitType.WALK;
			SectionList sectionList = this.linkSection(transitType, oa, ta, routeRequest);
			if (sectionList != null) {
				int pos = 0;
				routeResult.addSectionList(sectionList, pos);
			}
		}
		if (true) { // linek section TB -> OB
			TransitType transitType = TransitType.WALK;
			SectionList sectionList = this.linkSection(transitType, tb, ob, routeRequest);
			if (sectionList != null) {
				int pos = -1;
				routeResult.addSectionList(sectionList, pos);
			}
		}

		return routeResult;
	}

	private SectionList linkSection(TransitType transitType, Node s, Node e, RouteRequest routeRequest) throws Exception {
		if (s == null || e == null) {
			// do nothing !!!
			return null;
		} else {
			StartEndNode seNode = new StartEndNode(transitType, s, e);
			SectionList sectionList = this.getSectionList(seNode, routeRequest);

			double directConnectCoeff = transitType.getDirectConnectCoeff();

			// 보행, 자전기 이용시 거리가 직선 거리와 곡선 거리가 일정 수준이상 차이나면 , 직선으로 연결한다.
			if (directConnectCoeff <= 0) {
				// 직선 연결 계수가 0보다 같거나 작을 때는 직선 연결 섹션을 만들지 않는다.
			} else if (!routeRequest.isEnableDirectConnectCoeff()) {
				// 직선 연결 계수를 사용하지 않을 때....
				// do nothing !!!!
			} else if (transitType == TransitType.WALK || transitType == TransitType.BIKE) {
				double dirDist = s.getDirectDistance_Meter(e);
				double curvDist = sectionList.getCurveDistance_Meter();
				if (curvDist > dirDist * directConnectCoeff) {
					SectionList sectionList_Direct = new DirectLinkSection().getDirectSectionList(transitType, s, e);
					if (sectionList_Direct != null) {
						return sectionList_Direct;
					}
				}
			} // 끝. 직선 연결

			return sectionList;
		}
	}
}
